package com.yuanzi.base.aspect;

import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.regex.Pattern;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.stereotype.Component;

import com.yuanzi.base.annotation.Check;
import com.yuanzi.base.annotation.Length;
import com.yuanzi.base.annotation.Match;
import com.yuanzi.base.annotation.NotNull;
import com.yuanzi.base.annotation.Validate;
import com.yuanzi.base.util.ResultUtils;
import com.yuanzi.base.util.StringUtils;

/**
 * 参数校验注解
 * 在方法上添加@Valid注解<br>
 * 方法参数上添加@NotNull校验非空<br>
 * 方法参数上添加@Legth检验字符串长度<br>
 * 方法参数上添加@Matcher 校验字符串正则匹配<br>
 * @author chengshx
 * @date 2017年6月19日
 */
@Aspect
@Component
public class ValidateAspect {

	@Around("@annotation(validate)")
	public Object validate(ProceedingJoinPoint proceedingJoinPoint, Validate validate) throws Throwable {
		// 根据方法签名获取实际方法
		MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
		Method method = signature.getMethod();
		Parameter[] params = method.getParameters();
		// 获取参数的值
		Object[] values = proceedingJoinPoint.getArgs();
		Object result = null;
		// 获取参数名称
		ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
		String[] parameterNames = parameterNameDiscoverer.getParameterNames(method);
		// 循环校验方法的每个字段
		for(int i = 0; i < values.length; i++) {
			Annotation[] annotations = params[i].getAnnotations();
			for(Annotation annotation : annotations) {
				result = doValidate(parameterNames[i], values[i], annotation);
				if(result != null) return result;
			}
		}
		result = proceedingJoinPoint.proceed();
		return result;
	}

	/**
	 * 按不同注解类型进行校验
	 * @author chengshx
	 * @date 2017年6月22日
	 *
	 * @param name 参数名称
	 * @param value 参数的值
	 * @param annotation 注解
	 * @return
	 * @throws Exception
	 */
	private String doValidate(String name, Object value, Annotation annotation) throws Exception {
		String result = null;
		if(annotation instanceof NotNull) {
			NotNull notNull = (NotNull)annotation;
			result = validateNotNull(name, value, notNull.value());
		} else if (annotation instanceof Length) {
			Length length = (Length) annotation;
			// 长度校验参数名称
			String prompt = length.prompt();
//			if(StringUtils.isEmpty(prompt)) {
//				prompt = name;
//			}
			result = validateLength(prompt, value, length.min(), length.max(), length.notNull());
		} else if (annotation instanceof Check) {
			result = validateVO(name, value);
		} else if (annotation instanceof Match) {
			Match pattern = (Match) annotation;
			result = validatePattern(name, value, pattern.value());
		}
		return result;
	}
	
	/**
	 * 校验非空
	 * @author chengshx
	 * @date 2017年6月21日
	 *
	 * @param name 参数名称
	 * @param value 参数的值
	 * @param isEmpty 是否校验空字符
	 * @return
	 */
	private String validateNotNull(String name, Object value, boolean isEmpty) {
		boolean isNull = false;
		if(isEmpty && value instanceof String) {
			isNull = StringUtils.isEmpty(String.valueOf(value));
		} else {
			if(value == null) {
				isNull = true;
			} 
//			else if(value instanceof Number) {
//				String valStr = String.valueOf(value);
//				if(Objects.equals(valStr, "0")) isNull = true;
//			}
		}
		return isNull ? ResultUtils.getResult("0026", new Object[]{name}).toJSONString() : null;
	}
	
	/**
	 * 校验字符串长度
	 * @author chengshx
	 * @date 2017年6月21日
	 *
	 * @param value 参数的值
	 * @param min 最小长度
	 * @param max 最大长度
	 * @return
	 */
	private String validateLength(String name, Object value, int min, int max, boolean notNull) {
		String result = null;
		// 校验非空
		if(notNull) {
			result = validateNotNull(name, value, false);
			if(result != null) return result;
		}
		// 校验长度
		if(value != null) {
			String valStr = String.valueOf(value).trim();
			if(valStr.length() < min || valStr.length() > max) {
				return ResultUtils.getResult("0002", new Object[]{name, min, max}).toJSONString();
			}
		}
		return result;
	}
	
	/**
	 * 检验VO
	 * @author chengshx
	 * @date 2017年6月22日
	 *
	 * @param name vo名称
	 * @param vo VO实例对象
	 */
	private String validateVO(String name, Object vo) throws Exception {
		String result = null;
		// 校验非空
		result = validateNotNull(name, vo, false);
		if(result != null) return result;
		// 校验VO字段
		Class<?> clazz = vo.getClass();
		Field[] fields = clazz.getDeclaredFields();
		for(Field field : fields) {
			Annotation[] annotations = field.getAnnotations();
			for(Annotation annotation : annotations) {
				Object value = getFieldVal(clazz, vo, field);
				result = doValidate(field.getName(), value, annotation);
				if(result != null) return result;
			}
		}
		return result;
	}
	
	/**
	 * 正则匹配字段的值
	 * @author cui
	 * @param name 参数名称
	 * @param value 参数的值
	 * @param pattern 正则表达式
	 * @return
	 */
	private String validatePattern(String name, Object value, String pattern) throws Exception {
		String result = null;
		if(StringUtils.isEmpty(pattern)) {
			return result;
		}
		// 校验非空
		result = validateNotNull(name, value, false);
		if(result != null) return result;
		if(value instanceof String) {
			String valStr = String.valueOf(value);
			if (!Pattern.matches(pattern, valStr)) {
				return ResultUtils.getResult("0019", new Object[]{name}).toJSONString();
			}
		}
		return result;
	}
	
	/**
	 * 反射获取字段的值
	 * @author chengshx
	 * @date 2017年6月22日
	 *
	 * @param clazz VO类
	 * @param instance VO实例对象
	 * @param field VO字段
	 * @return
	 * @throws Exception
	 */
	private Object getFieldVal(Class<?> clazz, Object instance, Field field) throws Exception {
		// 获得get方法 
		PropertyDescriptor pd = new PropertyDescriptor(field.getName(), clazz);  
        Method method = pd.getReadMethod();
		return method.invoke(instance);
	}
	
}